﻿using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;

namespace Xms.Abp.Core;

public class DefaultDistributedSemaphoreProvider : IDistributedSemaphoreProvider, ISingletonDependency
{
    public string Name => "Default";

    private static ConcurrentDictionary<string, SemaphoreSlim> SemaphoreSlims { get; } = new();

    private static SemaphoreSlim GetSemaphoreSlim(string semaphoreName, int initialCount = 1)
    {
        return SemaphoreSlims.GetOrAdd(semaphoreName, s => new SemaphoreSlim(initialCount));
    }

    public bool Release(string semaphoreName, int releaseCount = 1)
    {
        if (!SemaphoreSlims.ContainsKey(semaphoreName)) return false;

        var result = SemaphoreSlims[semaphoreName].Release(releaseCount);

        return result == releaseCount;
    }

    public Task<bool> ReleaseAsync(string semaphoreName, int releaseCount = 1, CancellationToken cancellationToken = default)
    {
        return Task.FromResult(Release(semaphoreName, releaseCount));
    }

    public bool CheckSemaphore(string semaphoreName, TimeSpan timeout, int initialCount = 1)
    {
        return GetSemaphoreSlim(semaphoreName, initialCount).Wait(timeout);
    }

    public Task<bool> CheckSemaphoreAsync(string semaphoreName, TimeSpan timeout, int initialCount = 1, CancellationToken cancellationToken = default)
    {
        return GetSemaphoreSlim(semaphoreName, initialCount).WaitAsync(timeout, cancellationToken);
    }

    public void Dispose(string semaphoreName)
    {
        SemaphoreSlims.TryRemove(semaphoreName, out _);
    }
}
